package cn.iocoder.yudao.adminserver.franky.java8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamBase {

    public static void main(String[] args) {
        // 集合流
        List<String> list = Arrays.asList("a", "b", "c");
        Stream<String> listStream = list.stream();
        Stream<String> listParallelStream = list.parallelStream();

        // 数组流
        int[] array = {1, 2, 3, 3, 9, 5, 6};
        IntStream arrayStream = Arrays.stream(array);

        //stream 静态方法： of(), iterate(), generate()
        Stream<Integer> streamOf = Stream.of(1, 2, 3, 4, 5, 6);
        Stream<Integer> streamIterate = Stream.iterate(0, (x) -> x + 3).limit(4);
        streamIterate.forEach(System.out::println);

        //TODO franky Supplier
        Stream<Double> stream2 = Stream.generate(Math::random).limit(3);
        stream2.forEach(System.out::println);

        List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        // TODO franky  Optional
        // 顺序流转成并行流 Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true，调用get()方法会返回该对象
        Optional<Integer> findFirst = list2.stream().parallel().filter(x -> x > 5).findFirst();


        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, "male", "New York"));
        personList.add(new Person("Jack", 7000, "male", "Washington"));
        personList.add(new Person("Lily", 7800, "female", "Washington"));
        personList.add(new Person("Anni", 8200, "female", "New York"));
        personList.add(new Person("Owen", 9500, "male", "New York"));
        personList.add(new Person("Alisa", 7900, "female", "New York"));


        /** ===============================================遍历 foreach / find / match=============================================== */
        // -1
        List<Integer> listEach = Arrays.asList(7, 6, 9, 3, 8, 2, 1, 7);
        listEach.stream().filter(x -> x > 3).distinct().forEach(System.out::println);
        System.out.println(">>>>>>>split<<<<<<< ");
        // 遍历输出符合条件的元素
        listEach.stream().filter(x -> x > 3).forEach(System.out::println);
        // 匹配第一个
        Optional<Integer> f = listEach.stream().filter(x -> x > 2).findFirst();
        // 匹配任意（适用于并行流）
        Optional<Integer> any = listEach.parallelStream().filter(x -> x > 1).findAny();
        // 是否包含符合特定条件的元素
        boolean match = listEach.stream().anyMatch(x -> x < 6);
        System.out.println("匹配第一个：" + (f.orElse(null)));
        System.out.println("匹配任意：" + any.orElse(null));
        System.out.println("是否包含特性元素" + match);


        // ===============================================筛选，filter====================================================
        // -2
        List<Integer> filterList = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
        filterList.stream().filter(x -> x > 8).forEach(System.out::println);
        //-3
        List<String> personNameList = personList.stream().filter(s -> s.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
        System.out.println("工资高于8000的员工: " + personNameList);

        //===============================================聚合，max，min，count====================================================
        //-4
        List<String> listMax = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
        Optional<String> maxString = listMax.stream().max(Comparator.comparing(String::length));
        System.out.println("最长的字符串是: " + maxString);
        //-5
        List<Integer> integerMax = Arrays.asList(7, 6, 9, 4, 11, 6);
        Optional<Integer> maxInt = integerMax.stream().max(Integer::compareTo);
        // TODO franky 如果这里 写成o2.compareTo(o1)呢
        Optional<Integer> ownMaxInt = integerMax.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        ownMaxInt = integerMax.stream().max(Integer::compareTo);
        Optional<Integer> owno2o1Int = integerMax.stream().max((o1, o2) -> o2.compareTo(o1));
        Optional<Integer> ownMinInt = integerMax.stream().min(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println("自然排序max值：" + maxInt.get());
        System.out.println("自定义排序排序max的值：" + ownMaxInt.get());
        System.out.println("自定义排序排序min的值：" + ownMinInt.get());
        //-6
        Optional<Person> maxSalary = personList.stream().max(Comparator.comparingInt(Person::getSalary));
//	    System.out.println("员工工资最大值：" + maxSalary.get().getSalary());
        maxSalary.ifPresent(p -> System.out.println("员工工资最大值:" + maxSalary.get().getSalary()));

        //-7
        List<Integer> countList = Arrays.asList(7, 6, 4, 8, 2, 11, 9);

        long count = countList.stream().filter(x -> x > 6).count();
        System.out.println("list中大于6的元素个数：" + count);


        //===============================================映射 map/ flatMap====================================================
        /**
         * 映射，可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap：
         map：接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
         flatMap：接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流。
         */
        //-8 英文字符串数组的元素全部改为大写。整数数组每个元素+3
        String[] strArr = {"abcd", "bcdd", "defde", "fTr"};
        List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());

        List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
        List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
        List<Boolean> booList = intList.stream().map(x -> x > 3).collect(Collectors.toList());
        System.out.println("每个元素大写：" + strList);
        System.out.println("每个元素+3：" + intListNew);
        System.out.println("判断函数放到map映射：" + booList);

        //-9 将员工的薪资全部增加1000。
        // 不改变原来员工集合的方式
        List<Person> personListNew = personList.stream().map(person -> {
            Person personNew = new Person(person.getName(), 0, 0, null, null);
            personNew.setSalary(person.getSalary() + 10000);
            return personNew;
        }).collect(Collectors.toList());
        System.out.println("一次改动前：" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
        System.out.println("一次改动后：" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());

        // 改变原来员工集合的方式
        List<Person> personListNew2 = personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 10000);
            return person;
        }).collect(Collectors.toList());

        //		peek、foreach区别
        //		peek不会中断流，后面可以对流继续操作，foreach会中断流，只能进行遍历，也就是peek返回的是Stream，foreach返回的是void，遍历之后结束
        // franky  peek， peek 适用于修改数据，map 可以用来修改数据类型，因为map是return 返回一个新的类型【也可以是原先的】
//        personList.forEach(c -> c.setSalary(123));
        personListNew2 = personList.stream().peek(person -> person.setSalary(person.getSalary() + 10000)).collect(Collectors.toList());
        System.out.println(">>>>>>>>> peek:" + personListNew2);
        personListNew2 = personList.stream().peek(person -> {
            person.setSalary(person.getSalary() + 10000);
            person.setAge(101);
        }).collect(Collectors.toList());
        System.out.println(">>>>>>>>> peek 修改多个属性：" + personListNew2);
        // 这里当model的用@Data注释，这时候set方法返回的是this，而不是void，当set返回是void的时候，这里不能这么写
//		personListNew2 = personList.stream().map(person -> person.setSalary(person.getSalary() + 10000)).collect(Collectors.toList());
        personListNew2 = personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 10000);
            return person;
        }).collect(Collectors.toList());


        System.out.println("二次改动前：" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
        System.out.println("二次改动后：" + personListNew2.get(0).getName() + "-->" + personListNew2.get(0).getSalary());

        // -10 将两个字符数组合并成一个新的字符数组。
        List<String> listOriginal = Arrays.asList("m,k,l,a", "1,3,5,7");
        List<String> listNew = listOriginal.stream().flatMap(s -> {
            // 将每个元素转换成一个stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());

        System.out.println("处理前的集合：" + listOriginal);
        System.out.println("处理后的集合：" + listNew);


    }

}
